﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace CompilerPhase4
{
    public class Parser
    {
        #region FIELDS

        LexicalAnalyzer lexical; //Current token
        bool traceOn;  //En/disable trace comments
        Token currentToken; //current token being parsed.
        bool errorFound; //If an error is found
        int lineNumber;
        string line; //holds the data of a single line for output
        public QuadTable quad;

        const int PLACEHOLDER = 0; //Return value for each non-term, TBReplaced

        #endregion

        public Parser(LexicalAnalyzer lex, bool trace)
        {
            lexical = lex;
            traceOn = trace;
            errorFound = false;
            line = "";
            lineNumber = 0;
            currentToken = lex.NextToken();
            quad = new QuadTable(1000);
        }

        public void Run()
        {
            Program();
        }
        #region PRINTING METHODS
        [DebuggerNonUserCode]
        private void ErrorMsg(string error)
        {
            Console.WriteLine("\nERROR: " + error + " expected but " + 
                currentToken.Mnemonic + " found.");
        }
        [DebuggerNonUserCode]
        private void Msg(string msg) 
        {
            if (traceOn == true)
            {
                Console.WriteLine(msg);
            }
        }
        [DebuggerNonUserCode]
        private void Output()
        {
            if (traceOn == true) //Printing "VERBOSE"
            {
                Console.WriteLine("\n TOKEN: " + currentToken.Lexeme + "\t" + 
                    " TOKEN CODE: " + currentToken.Mnemonic + " " +
                    currentToken.TokenCode + "\n");
            }
        }
        private void PrintLine()
        {
            if (lineNumber < lexical.GetLineNumber)
            {
                lineNumber = lexical.GetLineNumber;
                line = lexical.GetSourceLine;
                Console.WriteLine("Line " + lineNumber + ": " +
                    currentToken.Lexeme + " " + line + "\n");
            }
        }
        #endregion
        #region EXPRESSION BUILDERS
        /*--------------------------------------------------------------------|
         * IDENTIFIER:  parser updated                                        |
         * ------------------------------------------------------------------*/
        private int Identifier()
        {
            int temp;
            Msg("ENTERING 'IDENTIFIER'");
            const int IDENT = 1; //Token Code for identifiers
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == IDENT)
            {
                temp = lexical.LookUpSymbol(currentToken.Lexeme);
                lexical.GetNextToken();
            }
            else
            {
                temp = -1;
                ErrorMsg("IDENTIFIER");
                errorFound = true;
            }
            Output();
            Msg("EXITING 'IDENTIFIER'");
            return temp;
        }
        /*--------------------------------------------------------------------|
         * UNSIGNED INTEGER                                                   |
         * ------------------------------------------------------------------*/
        private int UnsignedInteger()
        {
            Msg("ENTERING 'UNSIGNED INTEGER'");
            const int UNINT = 3; //Token code for integers
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == UNINT)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("UNSIGNED INTEGER");
                errorFound = true;
            }
            Output();
            Msg("EXITING 'UNSIGNED INTEGER'");
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * UNSIGNED NUMBER                                                    |
         * ------------------------------------------------------------------*/
        private int UnsignedNumber()
        {
            Msg("ENTERING 'UNSIGNED NUMBER'");
            UnsignedInteger();
            Msg("EXITING 'UNSIGNED NUMBER'");
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * UNSIGNED CONSTANT                                                  |
         * ------------------------------------------------------------------*/
        private int UnsignedConstant()
        {
            Msg("ENTERING 'UNSIGNED CONSTANT'");
            UnsignedNumber();
            Msg("EXITING 'UNSIGNED CONSTANT'");
            
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * ADDOP                                                              |
         * ------------------------------------------------------------------*/
        private int AddOp()
        {
            Msg("ENTERING 'ADDOP'");
            const int ADD = 10; //Token code for ADD
            const int MIN = 13; //Token code for MINUS
            int opCode;
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == ADD || currentToken.TokenCode == MIN)
            {
                lexical.GetNextToken();
                if (currentToken.TokenCode == ADD)
                {
                    opCode = 4;
                }
                else
                {
                    opCode = 3;
                }
            }
            else
            {
                ErrorMsg("ADDOP");
                errorFound = true;
                opCode = 0;
            }
            
            Output();
            Msg("EXITING 'ADDOP'");
            return opCode;
        }
        /*--------------------------------------------------------------------|
         * SIGN                                                               |
         * ------------------------------------------------------------------*/
        private int Sign()
        {
            Msg("ENTERING 'SIGN'");
            const int ADD = 10; //Token code for ADD
            const int MIN = 13; //Token code for MINUS
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == ADD || currentToken.TokenCode == MIN)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("SIGN");
                errorFound = true;
            }
            Output();
            Msg("EXITING 'SIGN'");
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * CONSTANT                                                           |
         * ------------------------------------------------------------------*/
        private int Constant()
        {
            Msg("ENTERING 'CONSTANT'");
            const int ADD = 10; //Token code for ADD
            const int MIN = 13; //Token code for MINUS
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == ADD || currentToken.TokenCode == MIN)
            {
                Sign();
            }
            UnsignedConstant();
            Msg("EXITING 'CONSTANT'");
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * SUBRANGE                                                           |
         * ------------------------------------------------------------------*/
        private int Subrange()
        {
            Msg("ENTERING 'SUBRANGE'");
            Constant();
            const int SUBRANGE = 34;
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == SUBRANGE)
            {
                Output();
                lexical.GetNextToken();
                Constant();
            }
            else
            {
                ErrorMsg("'..'");
            }
            Msg("EXITING SUBRANGE'");
            
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * SIMPLE_TYPE                                                        |
         * ------------------------------------------------------------------*/
        private int SimpleType()
        {
            Msg("ENTERING 'SIMPLE TYPE'");
            const int INTGRL = 85;
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == INTGRL)
            {
                Output();
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("SIMPLE TYPE");
                errorFound = true;
            }
            Msg("EXITING 'SIMPLE TYPE'");

            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * TYPE                                                               |
         * ------------------------------------------------------------------*/
        private int Type()
        {
            Msg("ENTERING 'TYPE'");
            const int SIMP = 85;
            const int ARRAY = 40;
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == SIMP)
            {
                SimpleType();
            }
            else if (currentToken.TokenCode == ARRAY)
            {
                const int LBRA = 25;
                const int RBRA = 26;
                const int OF = 56;
                Output();
                lexical.GetNextToken();
                currentToken = lexical.NextToken();
                if (currentToken.TokenCode == LBRA)
                {
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                    Subrange();
                    Output();
                    currentToken = lexical.NextToken();
                    if (currentToken.TokenCode == RBRA)
                    {
                        Output();
                        lexical.GetNextToken();
                        currentToken = lexical.NextToken();
                        if (currentToken.TokenCode == OF)
                        {
                            Output();
                            lexical.GetNextToken();
                            currentToken = lexical.NextToken();
                            Type();
                        }
                        else
                        {
                            errorFound = true;
                            ErrorMsg("TYPE");
                        }
                    }
                }
            }
            Msg("EXITING 'TERM'");
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * MULOP                                                              |
         * ------------------------------------------------------------------*/
        private int MulOp()
        {
            Msg("ENTERING 'MULOP'");
            const int MUL = 12; //Token code for ADD
            const int DIV = 16; //Token code for MINUS
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == MUL || currentToken.TokenCode == DIV)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("MULOP");
                errorFound = true;
            }
            Output();
            Msg("EXITING 'MULOP'");
            return PLACEHOLDER;
        }
        #endregion
        #region STATEMENT BUILDERS
        /*--------------------------------------------------------------------|
         * VARIABLE                                                           |
         * -------------------------------------------------------------------*/
        private int Variable()
        {
            Msg("ENTERING 'VARIABLE'");
            const int IDENT = 1;
            const int LBRK = 25;
            const int RBRK = 26;
            const int COMMA = 20;
            currentToken = lexical.NextToken();
            int temp = -1;
            if (currentToken.TokenCode == IDENT)
            {
                temp = Identifier();
                currentToken = lexical.NextToken();
                if (currentToken.TokenCode == LBRK)
                {
                    Output();
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                    SimpleExpression();
                    currentToken = lexical.NextToken();
                    while (currentToken.TokenCode == COMMA)
                    {
                        Output();
                        lexical.GetNextToken();
                        currentToken = lexical.NextToken();
                        SimpleExpression();
                    }
                    currentToken = lexical.NextToken();
                    if (currentToken.TokenCode == RBRK)
                    {
                        Output();
                        lexical.GetNextToken();
                    }
                    else
                    {
                        errorFound = true;
                        ErrorMsg("RBRK");
                    }
                }
            }
            else
            {
                errorFound = true;
                ErrorMsg("VAR");
            }
            Msg("EXITING 'VARIABLE'");
            return temp;
        }
        /*--------------------------------------------------------------------|
         * FACTOR      REDONE                                                 |
         * ------------------------------------------------------------------*/
        private int Factor()
        {
            Msg("ENTERING 'FACTOR'");
            const int INTGR = 3;
            const int IDNT = 1;
            const int LPAR = 22;
            const int RPAR = 23;
            currentToken = lexical.NextToken();
            int temp= 0;
            if (currentToken.TokenCode == INTGR)
            {
                UnsignedConstant();
            }
            else if (currentToken.TokenCode == IDNT)
            {
                Variable();
            }
            else if (currentToken.TokenCode == LPAR)
            {
                Output();
                lexical.GetNextToken();
                currentToken = lexical.NextToken();
                temp = SimpleExpression();
                if (currentToken.TokenCode == RPAR)
                {
                    Output();
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("RPAR");
                }
            }
            else
            {
                errorFound = true;
                ErrorMsg("FACTOR");
            }
            Msg("EXITING 'FACTOR'");
            return temp;
        }
        /*--------------------------------------------------------------------|
         * TERM           REDONE                                              |
         * ------------------------------------------------------------------*/
        private int Term()
        {
            Msg("ENTERING 'TERM'");
            const int MUL = 12;
            const int DIV = 16;
            Symbol op1, op2, op3;
            op1 = new Symbol(currentToken.Lexeme, 1, Factor());
            currentToken = lexical.NextToken();
            while (currentToken != null && currentToken.TokenCode == MUL ||
                currentToken.TokenCode == DIV)
            {
                while (currentToken != null && currentToken.TokenCode == MUL)
                {
                    MulOp();
                    int MULOP = 2;
                    currentToken = lexical.NextToken();
                    op2 = new Symbol(currentToken.Lexeme, 1, Factor());
                    currentToken = lexical.NextToken();
                    int value = op1.Value * op2.Value;
                    op3 = new Symbol(value.ToString(), 1, value);
                    lexical.AddSymbol(currentToken.Lexeme, 1, value);
                    quad.AddQuad(MULOP, op1, op2, op3);
                    op1 = new Symbol(op3.Name, 1, op3.Value);
                }
                while (currentToken.TokenCode == DIV)
                {
                    MulOp();
                    int DIVOP = 1;
                    op2 = new Symbol(currentToken.Lexeme, 1, Factor());
                    currentToken = lexical.NextToken();
                    int value = op1.Value / op2.Value;
                    op3 = new Symbol(value.ToString(), 1, value);
                    lexical.AddSymbol(currentToken.Lexeme, 1, value);
                    quad.AddQuad(DIVOP, op1, op2, op3);
                    op1 = new Symbol(op3.Name, 1, op3.Value);
                }
            }
            Msg("EXITING 'TERM'");
            return op1.Value;
        }
        /*--------------------------------------------------------------------|
         * SIMPLE EXPRESSION      REDONE                                      |
         * ------------------------------------------------------------------*/
        private int SimpleExpression()
        {
            Msg("ENTERING 'SIMPLE EXPRESSION'");
            const int ADD = 10;
            const int MIN = 13;
            currentToken = lexical.NextToken();
            Symbol op1 = null;
            Symbol op2, op3;
            if (currentToken.TokenCode == ADD || currentToken.TokenCode == MIN)
            {
                Output();
                Sign();
                if (currentToken.TokenCode == MIN)
                {
                    op1 = new Symbol(currentToken.Lexeme, 1, Term());
                    int NEG = -1;
                    int MUL = 2;
                    op2 = new Symbol("Negated", 1, (op1.Value*NEG));
                    Symbol temp = new Symbol("temp", 1, -1);
                    quad.AddQuad(MUL, op1, temp, op2);
                    op1 = new Symbol(op2.Name, 1, op2.Value);
                }
            }
            else
            {
                op1 = new Symbol(currentToken.Lexeme, 1, Term());
            }
            while (currentToken.TokenCode == ADD || currentToken.TokenCode == MIN)
            {
                while(currentToken.TokenCode == ADD)
                {
                    int ADDOP = AddOp();
                    currentToken = lexical.NextToken();
                    op1 = new Symbol(currentToken.Lexeme, 1, Term());
                    currentToken = lexical.NextToken();
                    op2 = new Symbol(currentToken.Lexeme, 1, Term());
                    op3 = new Symbol("temp", 1, 0);
                    quad.AddQuad(ADDOP, op1, op2, op3);
                }
                while(currentToken.TokenCode == ADD)
                {
                    int MINOP = AddOp();
                    currentToken = lexical.NextToken();
                    op1 = new Symbol(currentToken.Lexeme, 1, Term());
                    currentToken = lexical.NextToken();
                    op2 = new Symbol(currentToken.Lexeme, 1, Term());
                    op3 = new Symbol("temp", 1, 0);
                    quad.AddQuad(MINOP, op1, op2, op3);
                }
            }
            Msg("EXITING 'SIMPLE EXPRESSION'");
            return op1.Value;
        }
        #endregion
        #region RELATIVE CALLS
        /*--------------------------------------------------------------------|
         * RELOP                                                              |
         * ------------------------------------------------------------------*/
        private int RelOp()
        {
            Msg("ENTERING 'RELOP'");
            const int EQ = 11;
            const int LSS = 15;
            const int GTR = 17;
            const int NEQ = 14;
            const int LEQ = 32;
            const int GEQ = 33;
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == EQ || currentToken.TokenCode == LSS
                || currentToken.TokenCode == GTR 
                || currentToken.TokenCode == NEQ
                || currentToken.TokenCode == LEQ
                || currentToken.TokenCode == GEQ)
            {
                lexical.GetNextToken();
            }
            else
            {
                ErrorMsg("RELOP");
                errorFound = true;
            }
            Output();
            Msg("EXITING 'RELOP'");
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * REL EXPRESSION                                                     |
         * ------------------------------------------------------------------*/
        private int RelExpression()
        {
            Msg("ENTERING 'REL EXPRESSSION'");
            SimpleExpression();
            RelOp();
            SimpleExpression();
            Msg("EXITING 'REL EXPRESSION'");
            return PLACEHOLDER;
        }
        #endregion
        /*--------------------------------------------------------------------|
         * STATEMENT                                                          |
         * ------------------------------------------------------------------*/
        private int Statement()
        {
            PrintLine();
            Msg("ENTERING 'STATEMENT'");
            const int IDENT = 1;
            const int BEGIN = 41;
            const int IF = 51;
            const int WHILE = 67;
            const int REPEAT = 60;
            const int FOR = 49;
            const int LOOP = 53;
            const int GOTO = 86;
            const int WRTLN = 88;

            if (currentToken.TokenCode == IDENT)
            {
                #region IDENTIFIER
                line = lexical.GetSourceLine;
                const char COLON = ':';
                const char EQL = '=';
                if (line.Length == 1 || line[0] == COLON && line[1] != EQL)
                {
                    Identifier();
                    currentToken = lexical.NextToken();
                    Output();
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                    Statement();
                }
                else
                {
                    Symbol op1, op3;
                    string name = currentToken.Lexeme;
                    Variable();
                    currentToken = lexical.NextToken();
                    op1 = new Symbol(name, 1, 0);
                    Output();
                    const int ASSN = 30;
                    if (currentToken.TokenCode == ASSN)
                    {
                        lexical.GetNextToken();
                        currentToken = lexical.NextToken();
                        int temp = SimpleExpression();
                        int ASSNOP = 5;
                        op3 = new Symbol(temp.ToString(), 1, temp);
                        Symbol op2 = new Symbol("null", 0, 0);
                        quad.AddQuad(ASSNOP, op1, op2, op3);
                    }
                    else
                    {
                        errorFound = true;
                        ErrorMsg("ASSIGN expected but " +
                            currentToken.Lexeme + " found");
                    }
                }
                #endregion
            }
            else if (currentToken.TokenCode == BEGIN)
            {
                #region BEGIN
                lexical.GetNextToken();
                currentToken = lexical.NextToken();
                Statement();
                const int SCOLON = 21;
                while (currentToken.TokenCode == SCOLON)
                {
                    lexical.GetNextToken();
                    Output();
                    currentToken = lexical.NextToken();
                    Statement();
                }
                const int END = 47;
                if (currentToken.TokenCode == END)
                {
                    currentToken = lexical.NextToken();
                    Output();
                    lexical.GetNextToken();
                }
                else
                {
                    ErrorMsg("END");
                }
                #endregion
            }
            else if (currentToken.TokenCode == IF)
            {
                #region IF
                lexical.GetNextToken();
                Output();
                currentToken = lexical.NextToken();
                RelExpression();
                currentToken = lexical.NextToken();
                const int THEN = 62;
                if (currentToken.TokenCode == THEN)
                {
                    lexical.GetNextToken();
                    Output();
                    currentToken = lexical.NextToken();
                    Statement();
                    currentToken = lexical.NextToken();
                    const int ELSE = 46;
                    if (currentToken.TokenCode == ELSE)
                    {
                        lexical.GetNextToken();
                        Output();
                        currentToken = lexical.NextToken();
                        Statement();
                    }
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("THEN");
                }
#endregion
            }
            else if (currentToken.TokenCode == WHILE)
            {
                #region WHILE
                lexical.GetNextToken();
                Output();
                currentToken = lexical.NextToken();
                RelExpression();
                currentToken = lexical.NextToken();
                const int DO = 45;
                if (currentToken.TokenCode == DO)
                {
                    lexical.GetNextToken();
                    Output();
                    currentToken = lexical.NextToken();
                    Statement();
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("DO");
                }
                #endregion
            }
            else if (currentToken.TokenCode == REPEAT)
            {
                #region REPEAT
                const int UNTIL = 65;
                lexical.GetNextToken();
                Output();
                currentToken = lexical.NextToken();
                Statement();
                currentToken = lexical.NextToken();
                if (currentToken.TokenCode == UNTIL)
                {
                    lexical.GetNextToken();
                    Output();
                    currentToken = lexical.NextToken();
                    RelExpression();
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("UNTIL");
                }
                #endregion
            }
            else if (currentToken.TokenCode == FOR)
            {
                #region FOR
                lexical.GetNextToken();
                Output();
                currentToken = lexical.NextToken();
                Variable();
                const int ASSN = 30;
                currentToken = lexical.NextToken();
                if (currentToken.TokenCode == ASSN)
                {
                    const int DO = 45;
                    const int TO = 63;
                    lexical.GetNextToken();
                    Output();
                    currentToken = lexical.NextToken();
                    SimpleExpression();
                    currentToken = lexical.NextToken();
                    if (currentToken.TokenCode == TO)
                    {
                        lexical.GetNextToken();
                        Output();
                        currentToken = lexical.NextToken();
                        SimpleExpression();
                        currentToken = lexical.NextToken();
                        if (currentToken.TokenCode == DO)
                        {
                            lexical.GetNextToken();
                            Output();
                            currentToken = lexical.NextToken();
                            Statement();
                        }
                        else
                        {
                            errorFound = true;
                            ErrorMsg("DO");
                        }
                    }
                    else
                    {
                        errorFound = true;
                        ErrorMsg("TO");
                    }

                }
                else
                {
                    errorFound = true;
                    ErrorMsg("ASSN");
                }
                #endregion
            }
            else if (currentToken.TokenCode == LOOP)
            {
                #region LOOP
                lexical.GetNextToken();
                Output();
                currentToken = lexical.NextToken();
                Statement();
                if (currentToken.TokenCode == WHILE)
                {
                    lexical.GetNextToken();
                    Output();
                    currentToken = lexical.NextToken();
                    RelExpression();
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("DO");
                }
                #endregion
            }
            else if (currentToken.TokenCode == GOTO)
            {
                #region GOTO
                lexical.GetNextToken();
                Output();
                currentToken = lexical.NextToken();
                Identifier();
                #endregion
            }
            else if (currentToken.TokenCode == WRTLN)
            {
                #region WRITELINE
                const int LPAR = 22;
                const int RPAR = 23;
                lexical.GetNextToken();
                Output();
                currentToken = lexical.NextToken();
                if (currentToken.TokenCode == LPAR)
                {
                    lexical.GetNextToken();
                    Output();
                    currentToken = lexical.NextToken();
                    SimpleExpression();
                    currentToken = lexical.NextToken();
                    if (currentToken.TokenCode == RPAR)
                    {
                        lexical.GetNextToken();
                        Output();
                    }
                    else
                    {
                        errorFound = true;
                        ErrorMsg("RPAR");
                    }
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("LPAR");
                }
                #endregion
            }
            Msg("EXITING 'STATEMENT'");
            return PLACEHOLDER;          
        }
        /*--------------------------------------------------------------------|
         * BLOCK                                                              |
         * ------------------------------------------------------------------*/
        private int Block()
        {
            Msg("ENTERING 'BLOCK'");
            Console.WriteLine("");            
            const int LABEL = 89;
            const int VAR = 66;
            const int BEGIN = 41;
            #region LABEL
            if (currentToken.TokenCode == LABEL)
            {
                currentToken = lexical.NextToken();
                Output();
                lexical.GetNextToken();
                Identifier();
                const int COMMA = 20;
                currentToken = lexical.NextToken();
                while (currentToken.TokenCode == COMMA)
                {
                    currentToken = lexical.NextToken();
                    Output();
                    lexical.GetNextToken();
                    Identifier();
                    currentToken = lexical.NextToken();
                }
                const int SCOLN = 21;
                if (currentToken.TokenCode == SCOLN)
                {
                    currentToken = lexical.NextToken();
                    Output();
                    lexical.GetNextToken();
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("SCOLN");
                }
            }
            #endregion
            currentToken = lexical.NextToken();
            #region VAR DECLARATION
            if (currentToken.TokenCode == VAR)
            {
                while (currentToken.TokenCode == VAR)
                {
                    const int IDENT = 1;
                    const int COMMA = 20;
                    const int COLON = 28;
                    const int SCOLN = 21;
                    Output();
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                    if (currentToken.TokenCode == IDENT)
                    {
                        while (currentToken.TokenCode == IDENT)
                        {
                            Identifier();
                            currentToken = lexical.NextToken();
                            while (currentToken.TokenCode == COMMA)
                            {
                                currentToken = lexical.NextToken();
                                Output();
                                lexical.GetNextToken();
                                currentToken = lexical.NextToken();
                                Identifier();
                                currentToken = lexical.NextToken();
                            }
                            currentToken = lexical.NextToken();
                            if (currentToken.TokenCode == COLON)
                            {
                                currentToken = lexical.NextToken();
                                Output();
                                lexical.GetNextToken();
                                currentToken = lexical.NextToken();
                                Type();
                                currentToken = lexical.NextToken();
                                if (currentToken.TokenCode == SCOLN)
                                {
                                    currentToken = lexical.NextToken();
                                    Output();
                                    lexical.GetNextToken();
                                    currentToken = lexical.NextToken();
                                }
                                else
                                {
                                    errorFound = true;
                                    ErrorMsg("SCOLON");
                                }
                            }
                            else
                            {
                                errorFound = true;
                                ErrorMsg("COLON");
                            }
                        }
                    }
                    else
                    {
                        errorFound = true;
                        ErrorMsg("IDENT");
                    }
                }
            }
            else
            {
                errorFound = true;
                ErrorMsg("VAR");
            }
            #endregion
            currentToken = lexical.NextToken();
            #region BEGIN
            if (currentToken.TokenCode == BEGIN)
            {
                currentToken = lexical.NextToken();
                Output();
                lexical.GetNextToken();
                currentToken = lexical.NextToken();
                Statement();
                currentToken = lexical.NextToken();
                const int SCOLN = 21;
                while (currentToken.TokenCode == SCOLN)
                {
                    currentToken = lexical.NextToken();
                    Output();
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                    Statement();
                }
                const int END = 47;
                currentToken = lexical.NextToken();
                if (currentToken.TokenCode == END)
                {
                    currentToken = lexical.NextToken();
                    Output();
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("END");
                }
            }
            else
            {
                errorFound = true;
                ErrorMsg("BEGIN");
            }
            #endregion
            Msg("EXITING 'BLOCK'");
            return PLACEHOLDER;
        }
        /*--------------------------------------------------------------------|
         * PROGRAM                                                            |
         * ------------------------------------------------------------------*/
        private int Program()
        {
            Msg("ENTERING 'PROGRAM'");
            const int MODULE = 54;
            const int SCOLN = 21;
            const int PERIOD = 19;
            currentToken = lexical.NextToken();
            if (currentToken.TokenCode == MODULE)
            {
                Output();
                lexical.GetNextToken();
                currentToken = lexical.NextToken();
                Identifier();
                currentToken = lexical.NextToken();
                if (currentToken.TokenCode == SCOLN)
                {
                    Output();
                    lexical.GetNextToken();
                    currentToken = lexical.NextToken();
                    Block();
                    currentToken = lexical.NextToken();
                    if (currentToken.TokenCode == PERIOD)
                    {
                        Output();
                        lexical.GetNextToken();
                        currentToken = lexical.NextToken();
                    }
                    else
                    {
                        errorFound = true;
                        ErrorMsg("PERIOD");
                    }
                }
                else
                {
                    errorFound = true;
                    ErrorMsg("SCOLN");
                }
            }
            else
            {
                errorFound = true;
                ErrorMsg("MODULE");
            }
            Msg("EXITING 'PROGRAM'");
            return PLACEHOLDER;
        }
//-----------------------------------------------------------------------------
    }
}

